home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / libdemo / trackball.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  6KB  |  218 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    Implementation of a virtual trackball.
  19.  *    Implemented by Gavin Bell, lots of ideas from Thant Tessman and
  20.  *        the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
  21.  *
  22.  */
  23. #include "trackball.h"
  24.  
  25. /*
  26.  * This size should really be based on the distance from the center of
  27.  * rotation to the point on the object underneath the mouse.  That
  28.  * point would then track the mouse as closely as possible.  This is a
  29.  * simple example, though, so that is left as an Exercise for the
  30.  * Programmer.
  31.  */
  32. #define TRACKBALLSIZE  (0.8)
  33.  
  34. /*
  35.  * Local function prototypes (not defined in trackball.h)
  36.  */
  37. float tb_project_to_sphere(float, float, float);
  38. void normalize_quat(float [4]);
  39.  
  40. /*
  41.  * Ok, simulate a track-ball.  Project the points onto the virtual
  42.  * trackball, then figure out the axis of rotation, which is the cross
  43.  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
  44.  * Note:  This is a deformed trackball-- is a trackball in the center,
  45.  * but is deformed into a hyperbolic sheet of rotation away from the
  46.  * center.  This particular function was chosen after trying out
  47.  * several variations.
  48.  * 
  49.  * It is assumed that the arguments to this routine are in the range
  50.  * (-1.0 ... 1.0)
  51.  */
  52. void
  53. trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
  54. {
  55.     float a[3];    /* Axis of rotation */
  56.     float phi;    /* how much to rotate about axis */
  57.     float p1[3], p2[3], d[3];
  58.     float t;
  59.  
  60.     if (p1x == p2x && p1y == p2y)
  61.     {
  62.         vzero(q); q[3] = 1.0; /* Zero rotation */
  63.         return;
  64.     }
  65.  
  66. /*
  67.  * First, figure out z-coordinates for projection of P1 and P2 to
  68.  * deformed sphere
  69.  */
  70.     vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
  71.     vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
  72.  
  73. /*
  74.  *    Now, we want the cross product of P1 and P2
  75.  */
  76.     vcross(p2,p1,a);
  77.  
  78. /*
  79.  *    Figure out how much to rotate around that axis.
  80.  */
  81.     vsub(p1,p2,d);
  82.     t = vlength(d) / (2.0*TRACKBALLSIZE);
  83.     /*
  84.      * Avoid problems with out-of-control values...
  85.      */
  86.     if (t > 1.0) t = 1.0;
  87.     if (t < -1.0) t = -1.0;
  88.     phi = 2.0 * asin(t);
  89.  
  90.     axis_to_quat(a,phi,q);
  91. }
  92.  
  93. /*
  94.  *    Given an axis and angle, compute quaternion.
  95.  */
  96. void
  97. axis_to_quat(float a[3], float phi, float q[4])
  98. {
  99.     vnormal(a);
  100.     vcopy(a,q);
  101.     vscale(q,fsin(phi/2.0));
  102.     q[3] = fcos(phi/2.0);
  103. }
  104.  
  105. /*
  106.  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
  107.  * if we are away from the center of the sphere.
  108.  */
  109. static float
  110. tb_project_to_sphere(float r, float x, float y)
  111. {
  112.     float d, t, z;
  113.  
  114.     d = fsqrt(x*x + y*y);
  115.     if (d < r*M_SQRT1_2)      /* Inside sphere */
  116.     z = fsqrt(r*r - d*d);
  117.     else
  118.     {             /* On hyperbola */
  119.         t = r / M_SQRT2;
  120.         z = t*t / d;
  121.     }
  122.     return z;
  123. }
  124.  
  125. /*
  126.  * Given two rotations, e1 and e2, expressed as quaternion rotations,
  127.  * figure out the equivalent single rotation and stuff it into dest.
  128.  * 
  129.  * This routine also normalizes the result every RENORMCOUNT times it is
  130.  * called, to keep error from creeping in.
  131.  *
  132.  * NOTE: This routine is written so that q1 or q2 may be the same
  133.  * as dest (or each other).
  134.  */
  135.  
  136. #define RENORMCOUNT 97
  137.  
  138. void
  139. add_quats(float q1[4], float q2[4], float dest[4])
  140. {
  141.     static int count=0;
  142.     int i;
  143.     float t1[4], t2[4], t3[4];
  144.     float tf[4];
  145.  
  146.     vcopy(q1,t1); 
  147.     vscale(t1,q2[3]);
  148.  
  149.     vcopy(q2,t2); 
  150.     vscale(t2,q1[3]);
  151.  
  152.     vcross(q2,q1,t3);
  153.     vadd(t1,t2,tf);
  154.     vadd(t3,tf,tf);
  155.     tf[3] = q1[3] * q2[3] - vdot(q1,q2);
  156.  
  157.     dest[0] = tf[0];
  158.     dest[1] = tf[1];
  159.     dest[2] = tf[2];
  160.     dest[3] = tf[3];
  161.  
  162.     if (++count > RENORMCOUNT)
  163.     {
  164.         count = 0;
  165.         normalize_quat(dest);
  166.     }
  167. }
  168.  
  169. /*
  170.  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
  171.  * If they don't add up to 1.0, dividing by their magnitued will
  172.  * renormalize them.
  173.  *
  174.  * Note: See the following for more information on quaternions:
  175.  * 
  176.  * - Shoemake, K., Animating rotation with quaternion curves, Computer
  177.  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
  178.  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
  179.  *   graphics, The Visual Computer 5, 2-13, 1989.
  180.  */
  181. static void
  182. normalize_quat(float q[4])
  183. {
  184.     int i;
  185.     float mag;
  186.  
  187.     mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
  188.     for (i = 0; i < 4; i++) q[i] /= mag;
  189. }
  190.  
  191. /*
  192.  * Build a rotation matrix, given a quaternion rotation.
  193.  *
  194.  */
  195. void
  196. build_rotmatrix(float m[4][4], float q[4])
  197. {
  198.     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
  199.     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
  200.     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
  201.     m[0][3] = 0.0;
  202.  
  203.     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
  204.     m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
  205.     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
  206.     m[1][3] = 0.0;
  207.  
  208.     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
  209.     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
  210.     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
  211.     m[2][3] = 0.0;
  212.  
  213.     m[3][0] = 0.0;
  214.     m[3][1] = 0.0;
  215.     m[3][2] = 0.0;
  216.     m[3][3] = 1.0;
  217. }
  218.